/**
 * 文件名：****.java
 * 版权：Copyright Lightkit All Rights Reserved.
 * 描述：*****
 */
package com.lightkits.wms.domain.saveonhand.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.lightkits.common.db.entity.BdOnhandJournal;
import com.lightkits.common.db.entity.BdOnhandQuantity;
import com.lightkits.common.db.entity.FndEventTypeBase;
import com.lightkits.common.db.entity.event.BdEvent;
import com.lightkits.common.db.entity.event.BdEventRecord;
import com.lightkits.framework.common.exception.LightKitsBizException;
import com.lightkits.framework.common.logging.Logger;
import com.lightkits.framework.common.logging.LoggerFactory;
import com.lightkits.framework.common.model.CheckResult;
import com.lightkits.framework.common.model.IResult;
import com.lightkits.framework.common.utility.json.JsonUtil;
import com.lightkits.framework.common.utility.object.ObjectUtil;
import com.lightkits.framework.common.utility.object.ParseUtil;
import com.lightkits.framework.common.utility.validate.IntegrityValidator;
import com.lightkits.framework.redis.lock.annotation.RedisLock;
import com.lightkits.framework.soa.client.id.GetGlobalIDRequestType;
import com.lightkits.framework.soa.client.id.GetGlobalIDResponseType;
import com.lightkits.framework.soa.client.id.IDServiceClient;
import com.lightkits.wms.domain.commons.service.WmsCommonsService;
import com.lightkits.wms.domain.saveonhand.models.OnhandParams;
import com.lightkits.wms.domain.saveonhand.repo.BdEventRecordService;
import com.lightkits.wms.domain.saveonhand.repo.BdEventService;
import com.lightkits.wms.domain.saveonhand.repo.BdOnhandJourService;
import com.lightkits.wms.domain.saveonhand.repo.BdOnhandQuanService;
import com.lightkits.wms.domain.saveonhand.service.CreateEventDomain;
import com.lightkits.wms.domain.saveonhand.service.CreateOnhandDomain;
import com.lightkits.wms.domain.saveonhand.service.UseParamsDomain;
import com.lightkits.wms.dto.onhand.model.OnhandDTO;
import com.lightkits.wms.util.models.Constrants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * GetParamsDomainImpl
 *
 * @author jing.wei@hand-china.com
 * Created on 2019/2/21 1:25
 */
@Service
public class UseParamsDomainImpl implements UseParamsDomain {
    private static final Logger LOGGER = LoggerFactory.getLogger(UseParamsDomainImpl.class);

    private final CreateOnhandDomain createOnhandDomain;
    private final BdOnhandQuanService bdOnhandQuanService;
    private final BdOnhandJourService bdOnhandJourService;
    private final BdEventRecordService bdEventRecordService;
    private final BdEventService bdEventService;
    private final IDServiceClient idAdapterService;
    private final WmsCommonsService wmsCommonsService;
    private final CreateEventDomain eventDomain;

    @Autowired
    public UseParamsDomainImpl(CreateOnhandDomain createOnhandDomain,
                               BdOnhandQuanService bdOnhandQuanService,
                               BdOnhandJourService bdOnhandJourService,
                               BdEventRecordService bdEventRecordService,
                               BdEventService bdEventService,
                               IDServiceClient idAdapterService,
                               WmsCommonsService wmsCommonsService, CreateEventDomain eventDomain) {
        this.createOnhandDomain = createOnhandDomain;
        this.bdOnhandQuanService = bdOnhandQuanService;
        this.bdOnhandJourService = bdOnhandJourService;
        this.bdEventRecordService = bdEventRecordService;
        this.bdEventService = bdEventService;
        this.idAdapterService = idAdapterService;
        this.wmsCommonsService = wmsCommonsService;
        this.eventDomain = eventDomain;
    }

    /**
     * @param request 现有量参数
     * @return OnhandParams
     */
    @Override
    public CheckResult<OnhandParams> getOnhandParams(OnhandDTO request) {
        CheckResult<OnhandParams> checkResult = new CheckResult<>();
        OnhandParams param = new OnhandParams();
        if (ObjectUtil.isEmpty(request.getEventRequestId()) || request.getEventRequestId() == 0) {
            GetGlobalIDRequestType idRequest = new GetGlobalIDRequestType();
            idRequest.setCount(1);
            GetGlobalIDResponseType idResponse = idAdapterService.getGlobalId(idRequest);
            Iterator<Long> sfIds = idResponse.getIds().iterator();
            param.setEventRequestId(sfIds.next());
        } else {
            param.setEventRequestId(request.getEventRequestId());
        }
        IResult result = this.chackParams(request);
        if (!result.isSuccessful()) {
            checkResult.setData(param);
            result.fill(checkResult);
            return checkResult;
        }
        param.setEventTypeCode(request.getEventTypeCode());
        param.setOrgId(ParseUtil.tryLongWithException(request.getOrgId()));
        param.setItemId(ParseUtil.tryLongWithException(request.getItemId()));
        param.setUom(request.getUomCode());
        param.setQuantity(new BigDecimal(request.getChangeQuantity()));
        param.setChangeDirection(request.getChangeDirection());
        param.setPrimaryQuantity(param.getQuantity());
        param.setLotNumber(request.getLotNumber());
        param.setRemark(request.getRemark());
        param.setWarehouseId(ParseUtil.tryLongWithException(request.getWarehouseId()));
        if (!ObjectUtil.isNullOrEmpty(request.getWmAreaId())) {
            param.setWmAreaId(ParseUtil.tryLongWithException(request.getWmAreaId()));
        }
        param.setOwnerType(request.getOwnerType());
        if (!ObjectUtil.isNullOrEmpty(request.getOwnerId())) {
            param.setOwnerId(ParseUtil.tryLongWithException(request.getOwnerId()));
        }
        if (!ObjectUtil.isNullOrEmpty(request.getWorkerId())) {
            param.setWorkerId(ParseUtil.tryLongWithException(request.getWorkerId()));
        }
        if (!ObjectUtil.isNullOrEmpty(request.getParentEventId())) {
            param.setParentEventId(ParseUtil.tryLongWithException(request.getParentEventId()));
        }
        checkResult.setData(param);
        checkResult.setSuccessful(true);
        return checkResult;

    }

    /**
     * 参数校验
     *
     * @param request 请求参数
     * @return IResult
     */
    private IResult chackParams(OnhandDTO request) {
        try {
            IntegrityValidator.begin()
                    .validate(request.getOrgId(), "Organization Id")
                    .validate(request.getItemId(), "Item Id")
                    .validate(request.getUomCode(), "Uom")
                    .validate(request.getChangeQuantity(), "Quantity")
                    .validate(request.getWarehouseId(), "Warehouse Id")
                    .validate(request.getOwnerType(), "Owner Type")
                    .validate(request.getChangeDirection(), "Change Direction");
        } catch (LightKitsBizException e) {
            return e.result();
        }
        IResult result = wmsCommonsService.checkLocationParams(request.getWarehouseId(), request.getWmAreaId());
        if (!result.isSuccessful()) {
            return result;
        }
        if (request.getChangeDirection().equals(Constrants.OUT)) {
            result = wmsCommonsService.checkNegativestock(request.getWarehouseId(),
                    request.getWmAreaId(),
                    request.getChangeQuantity(),
                    request.getUomCode());
            if (!result.isSuccessful()) {
                return result;
            }
        }
        result = wmsCommonsService.checkOwnerParams(request.getOwnerType(),
                request.getOwnerId());
        if (!result.isSuccessful()) {
            return result;
        }
        FndEventTypeBase eventTypeBase = new FndEventTypeBase()
                .selectOne(new EntityWrapper<FndEventTypeBase>()
                        .eq(FndEventTypeBase.EVENT_TYPE_CODE, request.getEventTypeCode()));
        result = IResult.fail(request.getEventTypeCode() + "不存在或不是有效的事件类型编码");
        if (ObjectUtil.isEmpty(eventTypeBase)) {
            return result;
        }
        if (!request.getChangeDirection().equals(Constrants.OUT)
                && !request.getChangeDirection().equals(Constrants.IN)) {
            return result;
        }
        return IResult.success();
    }

    @Override
    @RedisLock(key = "UseParamsDomain.insertValue")
    @Transactional(rollbackFor = Exception.class)
    public CheckResult<String> insertValue(OnhandParams params) {
        CheckResult<String> checkResultRes = new CheckResult<>();
        checkResultRes.setSuccessful(true);
        //创建现有量参数
        CheckResult quantityCheckResult = createOnhandDomain.createOnhandQuan(params);
        if (!quantityCheckResult.isSuccessful()) {
            return quantityCheckResult.fill(checkResultRes);
        }
        BdOnhandQuantity quantity = (BdOnhandQuantity) quantityCheckResult.getData();
        if (ObjectUtil.isEmpty(quantity)) {
            throw new LightKitsBizException("The onhand quantity is empty");
        }
        bdOnhandQuanService.insertOrUpdate(quantity);

        checkResultRes.setData(quantity.getQuantity().toString());
        //创建事件 Event
        BdEvent event = eventDomain.createEvent(params);
        bdEventService.insert(event);
        //创建快照
        List<BdEventRecord> records = new ArrayList<>();
        BdEventRecord eventRecord = eventDomain.createEventRecord("ONHAND",
                params.getChangeDirection(), params.getQuantity().toString(), event.getId(),
                quantity.getId(), JsonUtil.toString(quantity));

        records.add(eventRecord);
        //创建库存日记账
        BdOnhandJournal journal = eventDomain.createOnhandJournal(quantity,
                event, params.getChangeDirection());
        bdOnhandJourService.insert(journal);
        BdEventRecord record = eventDomain.createEventRecord("ONHAND_JOURNAL",
                params.getChangeDirection(), params.getQuantity().toString(), event.getId(),
                journal.getId(), JsonUtil.toString(journal));
        records.add(record);
        if (ObjectUtil.isNullOrEmpty(records)) {
            throw new LightKitsBizException("Insert BeEvent Records is empty");
        }
        bdEventRecordService.insertBatch(records);

        return checkResultRes;

    }
}